package main

import "fmt"

//固定 worker 工作池
//以计算多个整数的和为例

// 工作池的 goroutine 数目
const (
	NUMBER = 10
)

// 工作任务
type task1 struct {
	begin  int
	end    int
	result chan<- int
}

// 任务处理：计算begin到end的和
// 执行结果写入结果chan result
func (t *task1) do() {
	sum := 0
	for i := t.begin; i <= t.end; i++ {
		sum += i
	}
	t.result <- sum
}

func main() {
	workers := NUMBER

	//工作通道
	taskchan := make(chan task1, 10)

	//结果通道
	resultchan := make(chan int, 10)

	//worker信号通道
	done := make(chan struct{}, 10)

	//初始化 task 的 goroutine，计算 100 个自然数之和
	go InitTask1(taskchan, resultchan, 100)

	//分发任务到 NUMBER 个 goroutine 池
	DistributeTask1(taskchan, workers, done)

	//获取各个 goroutine 处理完任务的通知，并关闭结果通道
	go CloseResult(done, resultchan, workers)

	//通过结果通道获取结果并汇总
	sum := ProcessResult1(resultchan)

	fmt.Println("sum = ", sum)
}

// 初始化待处理数据 task chan
func InitTask1(taskchan chan<- task1, r chan int, p int) {
	qu := p / 10
	mod := p % 10
	high := qu * 10
	for j := 0; j < qu; j++ {
		b := j*10 + 1
		e := 10 * (j + 1)
		tsk := task1{
			begin:  b,
			end:    e,
			result: r,
		}
		taskchan <- tsk
	}

	if mod != 0 {
		tsk := task1{
			begin:  high + 1,
			end:    p,
			result: r,
		}
		taskchan <- tsk
	}

	close(taskchan)
}

// 读取 task chan 并分发到 worker goroutine 处理，总的数量是 workers
func DistributeTask1(taskchan <-chan task1, workers int, done chan struct{}) {
	for i := 0; i < workers; i++ {
		go ProcessTask1(taskchan, done)
	}
}

// 工作 goroutine 处理具体工作，并将处理结果发送到结果 chan
func ProcessTask1(taskchan <-chan task1, done chan struct{}) {
	for t := range taskchan {
		t.do()
	}
	done <- struct{}{}
}

// 通过done channel 同步等待所有工作 goroutine 的结束，然后关闭结果 chan
func CloseResult(done chan struct{}, resultchan chan int, workes int) {
	for i := 0; i < workes; i++ {
		<-done
	}
	close(done)
	close(resultchan)
}

// 读取结果通道，汇总结果
func ProcessResult1(resultchan chan int) int {
	sum := 0
	for r := range resultchan {
		sum += r
	}
	return sum
}
